package com.jingdianjichi.auth.domain.service.impl;

//import cn.dev33.satoken.secure.SaSecureUtil;
import cn.dev33.satoken.secure.SaSecureUtil;
import cn.dev33.satoken.stp.SaTokenInfo;
import cn.dev33.satoken.stp.StpUtil;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.jingdianjichi.auth.common.enums.AuthUserStatusEnum;
import com.jingdianjichi.auth.common.enums.IsDeletedFlagEnum;
import com.jingdianjichi.auth.domain.constants.AuthConstant;
import com.jingdianjichi.auth.domain.convert.AuthUserBOConverter;
import com.jingdianjichi.auth.domain.entity.AuthPermissionBO;
import com.jingdianjichi.auth.domain.entity.AuthUserBO;
import com.jingdianjichi.auth.domain.redis.RedisUtil;
import com.jingdianjichi.auth.domain.service.AuthUserDomainService;
import com.jingdianjichi.auth.infra.basic.entity.*;
import com.jingdianjichi.auth.infra.basic.service.*;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors;

@Service
@Slf4j
public class AuthUserDomainServiceImpl implements AuthUserDomainService {

    @Resource
    private AuthUserService authUserService;
    @Resource
    private AuthRoleService authRoleService;
    @Resource
    AuthRolePermissionService authRolePermissionService;
    @Resource
    private AuthUserRoleService authUserRoleService;
    @Resource
    AuthPermissionService authPermissionService;

    private String salt = "chicken";
    @Resource
    RedisUtil redisUtil;
    private String authPermissionPrefix = "auth.permission";
    private String authRolePrefix = "auth.role";
    private String LOGIN_PREFIX = "login:";

    @Override
    public SaTokenInfo doLogin(String validateCode) {
        String Key = redisUtil.buildKey(LOGIN_PREFIX, validateCode);
        String openId = redisUtil.get(Key);
        if(StringUtils.isEmpty(openId)){
            return null;
        }
        AuthUserBO authUserBO = new AuthUserBO();
        authUserBO.setUserName(openId);
        this.register(authUserBO);
        StpUtil.login(openId);
        return StpUtil.getTokenInfo();
    }

    @Override
    @SneakyThrows
    @Transactional(rollbackFor = Exception.class)
    public Boolean register(AuthUserBO authUserBO) {
        AuthUser authUserExist = new AuthUser();
        authUserExist.setUserName(authUserBO.getUserName());
        if(authUserService.queryByCondition(authUserExist).isEmpty()){
            return true;
        }
        AuthUser authUser = AuthUserBOConverter.INSTANCE.convertBOToEntity(authUserBO);
        if(authUser.getPassword() != null){
            authUser.setPassword(SaSecureUtil.md5BySalt(authUser.getPassword(), salt));
        }

        authUser.setStatus(AuthUserStatusEnum.OPEN.getCode());
        authUser.setIsDeleted(IsDeletedFlagEnum.UN_DELETED.getCode());
        Integer count = authUserService.insert(authUser);
        //建立一个初步的角色的关联
        //要把当前用户的角色和权限都刷到我们的redis里
        //建立角色和用户的初始关系
        AuthRole authRole = new AuthRole();
        authRole.setRoleKey(AuthConstant.NORMAL_USER);
        AuthRole authRole1 = authRoleService.queryByCondition(authRole);
        AuthUserRole authUserRole = new AuthUserRole();
        authUserRole.setUserId(authUser.getId());
        authUserRole.setRoleId(authRole1.getId());
        authUserRole.setIsDeleted(IsDeletedFlagEnum.UN_DELETED.getCode());
        authUserRoleService.insert(authUserRole);
        //在缓存中建立角色和用户的关系（key使用前缀加用户名）
        String roleKey = redisUtil.buildKey(authRolePrefix, authUser.getUserName());
        List<AuthRole> authRoles = new ArrayList<>();
        //普通的角色对象集合
        authRoles.add(authRole1);
        redisUtil.set(roleKey, new Gson().toJson(authRoles));
        //在缓存中建立用户和权限的关系
        String permissionKey = redisUtil.buildKey(authPermissionPrefix, authUser.getUserName());
        //通过角色查出对应的权限
        AuthRolePermission authRolePermission = new AuthRolePermission();
        authRolePermission.setRoleId(authRole1.getId());
        List<AuthRolePermission> authRolePermissions = authRolePermissionService.queryByCondition(authRolePermission);
        List<Integer> collect = authRolePermissions.stream().map(AuthRolePermission::getPermissionId).collect(Collectors.toList());
        //最终查出的权限对象集合
        List< AuthPermission> authPermissions = authPermissionService.queryBatchByIds(collect);
        redisUtil.set(permissionKey, new Gson().toJson(authPermissions));
        return count > 0;
    }

    @Override
    public Boolean update(AuthUserBO authUserBO) {
        AuthUser authUser = AuthUserBOConverter.INSTANCE.convertBOToEntity(authUserBO);
        Integer count = authUserService.update(authUser);
        //有任何的更新，都要与缓存进行同步的修改
        return count > 0;
    }

    @Override
    public Boolean delete(AuthUserBO authUserBO) {
        AuthUser authUser = new AuthUser();
        authUser.setId(Math.toIntExact(authUserBO.getId()));
        authUser.setIsDeleted(IsDeletedFlagEnum.DELETED.getCode());
        Integer count = authUserService.update(authUser);
        //有任何的更新，都要与缓存进行同步的修改
        return count > 0;
    }

    @Override
    public AuthUserBO getUserInfo(AuthUserBO authUserBO) {
        AuthUser authUser = new AuthUser();
        authUser.setId(Math.toIntExact(authUserBO.getId()));
        List<AuthUser> authUsers = authUserService.queryByCondition(authUser);
        if(authUsers.isEmpty()){
            return new AuthUserBO();
        }
        return AuthUserBOConverter.INSTANCE.convertEntityToBO(authUsers.get(0));
    }

    @Override
    public List<String> getPermission(String userName) {
        String permissionKey = redisUtil.buildKey(authPermissionPrefix, userName);
        String permission = redisUtil.get(permissionKey);
        if(StringUtils.isEmpty(permission)){
            return new ArrayList<>();
        }
        List<AuthPermission> authPermissions = new Gson().fromJson(permission, new TypeToken<List<AuthPermission>>() {
        }.getType());
        return authPermissions.stream().map(AuthPermission::getPermissionKey).collect(Collectors.toList());
    }
}
